#include "group_db_wrapper.h"

#include "base/format_time.h"
#include <boost/algorithm/string.hpp>
#include <boost/typeof/typeof.hpp>

namespace imserver {

const int GroupDBWrapper::GROUP_MEMBER_DB_MOD = 5;

bool GroupDBWrapper::select_tb_group_id_seq(int64_t& seq) {
  mysqlpp::ScopedConnection cp(*conn_pool_);
  if (!cp) {
    LOG_ERROR("GroupDBWrapper::select_tb_group_id_seq --> get db conn failed.");
    return false;
  }

  std::ostringstream os;
  os << "SELECT group_id from tb_group_id_seq ORDER BY group_id DESC LIMIT 1";
  mysqlpp::Query query(cp->query(os.str()));
  try {
    mysqlpp::UseQueryResult ret = query.use();
    if (ret) {
      while (mysqlpp::Row row = ret.fetch_row()) {
        seq = (int64_t)row["group_id"];
      }
    }
  } catch (mysqlpp::Exception &e) {
    LOG_ERROR("GroupDBWrapper::select_tb_group_id_seq --> query_str:" << query.str() << " error:" << e.what());
    return false;
  }
  return true;
}

bool GroupDBWrapper::update_tb_group_id_seq() {
  mysqlpp::ScopedConnection cp(*conn_pool_);
  if (!cp) {
    LOG_ERROR("GroupDBWrapper::update_tb_group_id_seq --> get db conn failed.");
    return false;
  }

  std::ostringstream os;
  os << "UPDATE tb_group_id_seq SET group_id = group_id + 1";
  mysqlpp::Query query(cp->query(os.str()));
  try {
    if (!query.exec()) {
      LOG_ERROR("GroupDBWrapper::update_tb_group_id_seq --> query return false. query_str:" << query.str());
      return false;
    }
  } catch (mysqlpp::Exception &e) {
    LOG_ERROR("GroupDBWrapper::update_tb_group_id_seq --> query_str:" << query.str() << " error:" << e.what());
    return false;
  }
  return true;
}


bool GroupDBWrapper::select_tb_group_info(int64_t group_id, int32_t type, int64_t entity_id, GroupInfo& group_info) {
  if (group_id <= 0 && entity_id <= 0) {
    LOG_ERROR("GroupDBWrapper::select_tb_group_info --> error params. group_id:" << group_id << " type:" << type <<
        " entity_id:" << entity_id);
    return false;
  }
  mysqlpp::ScopedConnection cp(*conn_pool_);
  if (!cp) {
    LOG_ERROR("GroupDBWrapper::select_tb_group_info --> get db conn failed. group_id:" << group_id << " type:" << type <<
        " entity_id:" << entity_id);
    return false;
  }

  std::string tags;
  std::ostringstream os;
  os << "SELECT group_id, name, type, entity_id, tags, create_date, logo FROM tb_group_info WHERE";
  if (group_id > 0) {
    os << " group_id = " << group_id;
  } else {
    os << " entity_id = " << entity_id << " AND type = " << type;
  }
  os << " LIMIT 1";
  mysqlpp::Query query(cp->query(os.str()));
  try {
    mysqlpp::UseQueryResult ret = query.use();
    if (ret) {
      while (mysqlpp::Row row = ret.fetch_row()) {
        group_info.id = (int64_t)row["group_id"];
        group_info.name = (std::string)row["name"];
        group_info.type = (int32_t)row["type"];
        group_info.entity_id = (int64_t)row["entity_id"];
        tags = (std::string)row["tags"];
        group_info.create_date = base::ToTimestamp(((std::string)row["create_date"]));
        group_info.logo = (std::string)row["logo"];
      }
    }
  } catch (mysqlpp::Exception &e) {
    LOG_ERROR("GroupDBWrapper::select_tb_group_info --> query_str:" << query.str() << " error:" << e.what());
    return false;
  }

  if (group_info.id <= 0) {
    return true;
  }

  if (!tags.empty()) {
    group_info.tags = std::set<std::string>();
    std::vector<std::string> v;
    boost::split(v, tags, boost::is_any_of(","));
    group_info.tags.insert(v.begin(), v.end());
  }

  query.reset();
  query << "SELECT COUNT(member_id) AS member_count FROM tb_group_member_" << group_info.id % GROUP_MEMBER_DB_MOD <<
      " WHERE group_id = " << group_info.id << " LIMIT 1";
  try {
    mysqlpp::UseQueryResult ret = query.use();
    if (ret) {
      while (mysqlpp::Row row = ret.fetch_row()) {
        group_info.member_count = (int32_t)row["member_count"];
      }
    }
  } catch (mysqlpp::Exception &e) {
    LOG_ERROR("GroupDBWrapper::select_tb_group_info --> query_str:" << query.str() << " error:" << e.what());
  }

  LOG_INFO("GroupDBWrapper::select_tb_group_info --> ok. group_id:" << group_info.id << " type:" << type <<
      " entity_id:" << entity_id);
  return true;
}

bool GroupDBWrapper::update_tb_group_info(const GroupInfo& group_info) {
  if (group_info.id <= 0) {
    LOG_ERROR("GroupDBWrapper::update_tb_group_info --> error group_id. group_id:" << group_info.id);
    return false;
  }

  mysqlpp::ScopedConnection cp(*conn_pool_);
  if (!cp) {
    LOG_ERROR("GroupDBWrapper::update_tb_group_info --> get db conn failed. group_id:" << group_info.id);
    return false;
  }

  std::ostringstream os;
  for(std::set<std::string>::const_iterator it = group_info.tags.begin(); it != group_info.tags.end(); ++it) {
    if (it != group_info.tags.begin()) {
      os << ",";
    }
    os << *it;
  }
  std::string tags(os.str());

  os.str("");
  os << "INSERT INTO tb_group_info (group_id, name, type, entity_id, tags, create_date, logo) VALUES (" <<
      group_info.id << "," <<
      "\"" << group_info.name << "\"," <<
      group_info.type << "," <<
      group_info.entity_id << "," <<
      "\"" << tags << "\"," <<
      "\"" << base::FriendlyTime((time_t)group_info.create_date) << "\","
      "\"" << group_info.logo << "\")" <<
      " ON DUPLICATE KEY UPDATE ";
  if (!group_info.name.empty()) {
    os << " name = \"" << group_info.name << "\",";
  }
  if (group_info.type > 0) {
    os << " type = " << group_info.type << ",";
  }
  if (group_info.entity_id > 0) {
    os << " entity_id = " << group_info.entity_id << ",";
  }
  if (!tags.empty()) {
    os << " tags = \"" << tags << "\",";
  }
  if (!group_info.create_date > 0) {
    os << " create_date = \"" << base::FriendlyTime((time_t)group_info.create_date) << "\",";
  }
  if (!group_info.logo.empty()) {
    os << " logo = \"" << group_info.logo << "\",";
  }
  std::string queryStr(os.str());
  mysqlpp::Query query(cp->query(queryStr.substr(0, queryStr.size()-1)));
  try {
    if (!query.exec()) {
      LOG_ERROR("GroupDBWrapper::update_tb_group_info --> query return false. query_str:" << query.str());
      return false;
    }
  } catch (mysqlpp::Exception &e) {
    LOG_ERROR("GroupDBWrapper::update_tb_group_info --> query_str:" << query.str() << " error:" << e.what());
    return false;
  }
  LOG_INFO("GroupDBWrapper::update_tb_group_info --> ok. group_id:" << group_info.id);
  return true;
}


bool GroupDBWrapper::select_tb_group_member_m(int64_t group_id, int32_t status, std::set<int64_t>& member_ids) {
  mysqlpp::ScopedConnection cp(*conn_pool_);
  if (!cp) {
    LOG_ERROR("GroupDBWrapper::select_tb_group_member_m --> get db conn failed. group_id:" << group_id);
    return false;
  }

  mysqlpp::Query query(&(*cp));
  query << "SELECT member_id FROM tb_group_member_" << group_id % GROUP_MEMBER_DB_MOD <<
      " WHERE group_id = " << group_id <<
      " AND status = " << status;
  try {
    mysqlpp::UseQueryResult ret = query.use();
    if (ret) {
      while (mysqlpp::Row row = ret.fetch_row()) {
        member_ids.insert((int64_t)row["member_id"]);
      }
    }
  } catch (mysqlpp::Exception &e) {
    LOG_ERROR("GroupDBWrapper::select_tb_group_member_m --> query_str:" << query.str() << " error:" << e.what());
    return false;
  }

  LOG_INFO("GroupDBWrapper::select_tb_group_member_m --> ok. group_id:" << group_id << " res_count:" << member_ids.size());
  return true;
}

bool GroupDBWrapper::select_tb_group_member_g(int64_t uid, int32_t status, std::set<int64_t>& group_ids) {
  mysqlpp::ScopedConnection cp(*conn_pool_);
  if (!cp) {
    LOG_ERROR("GroupDBWrapper::select_tb_group_member_g --> get db conn failed. uid:" << uid);
    return false;
  }

  mysqlpp::Query query(&(*cp));
  for (int i = 0; i < GROUP_MEMBER_DB_MOD; ++i) {
    query << "SELECT group_id FROM tb_group_member_" << i <<
        " WHERE member_id = " << uid <<
        " AND status = " << status;
    try {
      mysqlpp::UseQueryResult ret = query.use();
      if (ret) {
        while (mysqlpp::Row row = ret.fetch_row()) {
          group_ids.insert((int64_t)row["group_id"]);
        }
      }
    } catch (mysqlpp::Exception &e) {
      LOG_ERROR("GroupDBWrapper::select_tb_group_member_g --> query_str:" << query.str() << " error:" << e.what());
    }
    query.reset();
  }

  LOG_INFO("GroupDBWrapper::select_tb_group_member_g --> ok. uid:" << uid << " res_count:" << group_ids.size());
  return true;
}

bool GroupDBWrapper::update_tb_group_member(int64_t group_id, int64_t uid, int32_t status) {
  mysqlpp::ScopedConnection cp(*conn_pool_);
  if (!cp) {
    LOG_ERROR("GroupDBWrapper::update_tb_group_member --> get db conn failed. group_id:" << group_id << " uid:" << uid <<
        " status:" << status);
    return false;
  }

  std::ostringstream os;
  os << "INSERT INTO tb_group_member_" << group_id % GROUP_MEMBER_DB_MOD << 
      "(group_id, member_id, status, create_date) VALUES (" <<
      group_id << "," <<
      uid << "," <<
      status << "," <<
      "\"" << base::FriendlyTime(time(NULL)) << "\")" <<
      " ON DUPLICATE KEY UPDATE status = " << status;
  mysqlpp::Query query(cp->query(os.str()));
  try {
    if (!query.exec()) {
      LOG_ERROR("GroupDBWrapper::update_tb_group_member --> query return false. query_str:" << query.str());
      return false;
    }
  } catch (mysqlpp::Exception &e) {
    LOG_ERROR("GroupDBWrapper::update_tb_group_member --> query_str:" << query.str() << " error:" << e.what());
    return false;
  }
  LOG_INFO("GroupDBWrapper::update_tb_group_member --> ok. group_id:" << group_id <<" uid:" << uid << " status:" << status);
  return true;
}

bool GroupDBWrapper::delete_tb_group_member(int64_t group_id, int64_t uid) {
  mysqlpp::ScopedConnection cp(*conn_pool_);
  if (!cp) {
    LOG_ERROR("GroupDBWrapper::delete_tb_group_member --> get db conn failed. group_id:" << group_id << " uid:" << uid);
    return false;
  }

  std::ostringstream os;
  os << "DELETE FROM tb_group_member_" << group_id % GROUP_MEMBER_DB_MOD <<
      " WHERE group_id = " << group_id <<
      " AND member_id = " << uid;
  mysqlpp::Query query(cp->query(os.str()));
  try {
    if (!query.exec()) {
      LOG_ERROR("GroupDBWrapper::delete_tb_group_member --> query return false. query_str:" << query.str());
      return false;
    }
  } catch (mysqlpp::Exception &e) {
    LOG_ERROR("GroupDBWrapper::delete_tb_group_member --> query_str:" << query.str() << " error:" << e.what());
    return false;
  }
  LOG_INFO("GroupDBWrapper::delete_tb_group_member --> ok. group_id:" << group_id <<" uid:" << uid);
  return true;
}

}

